﻿using UnityEngine;

public static class UnitExpandingFunction
{
    
    /// <summary>
    /// 锁定目标方向
    /// </summary>
    /// <param name="transform"></param>
    /// <param name="target"></param>
    /// <param name="self"></param>
    /// <param name="lerpTime"></param>
    /// <returns></returns>
    public static Quaternion LockOnTarget(this Transform transform, Transform target,Transform self,float lerpTime)
    {
        if (target == null) return self.rotation;

        Vector3 targetDirection = (target.position - self.position).normalized;
        targetDirection.y = 0f;
        Quaternion newRotation = Quaternion.LookRotation(targetDirection);

        return Quaternion.Lerp(self.rotation, newRotation, lerpTime * Time.deltaTime);
    }

    /// <summary>
    /// 看着目标方向以Y轴为中心
    /// </summary>
    /// <param name="transform"></param>
    /// <param name="target"></param>
    /// <param name="lerpTime">平滑时间(如果是单击某个按键触发那么值最好设置100以上。)</param>
    public static void Look(this Transform transform, Vector3 target,float lerpTime = 10f)
    {
        var pos = target;
        pos.y = 0f;
        var targetRotation = Quaternion.LookRotation(pos);
        transform.rotation = Quaternion.Slerp(transform.rotation,targetRotation,DragTimeE(lerpTime));
    }

    /// <summary>
    /// 阻力时间(可在Lerp函数中代替增量时间的使用),相比较DragTimeP，使用这个函数趋近目标值的速度会慢一点。
    /// </summary>
    /// <param name="time"></param>
    /// <returns></returns>
    public static float DragTimeE(float time)
    {
        //Mathf.Exp:自然数e的次方，即自然数e乘以多少次后的结果。
        return 1 - Mathf.Exp(-time * Time.deltaTime);
    }
        
    /// <summary>
    /// 阻力时间(可在Lerp函数中代替增量时间的使用)相比较DragTimeE，使用这个函数趋近目标值的速度会更快。
    /// 注意:在趋近与目标值时，变化会越来越小,不会真正抵达目标值,只会接近。
    /// </summary>
    /// <param name="time"></param>
    /// <returns></returns>
    public static float DragTimeP(float time)
    {
        return 1 - Mathf.Pow(time ,Time.deltaTime);
    }
    
    
    /// <summary>
    /// 限制一个值在0-360之间
    /// </summary>
    /// <param name="f"></param>
    /// <returns></returns>
    public static float ClampValue360(float f)
    {
        f %= 360f;
        if (f < 0)
            f += 360;

        return f;
    }
        
    /// <summary>
    /// 限制一个值在0-180之间
    /// </summary>
    /// <param name="f"></param>
    /// <returns></returns>
    public static float ClampValue180(float f)
    {
        f = (f + 180f) % 360f - 180f;

        if (f < -180)
            f += 360;

        return f;
    }
    
    /// <summary>
    /// 计算角速度
    /// </summary>
    /// <param name="quaternion"></param>
    /// <returns></returns>
    public static Vector3 CalculateAngularVelocity(Quaternion quaternion)
    {
        quaternion.ToAngleAxis(out float angleInDegrees, out Vector3 rotationAxis);

        Vector3 angularDisplacement = rotationAxis * angleInDegrees * Mathf.Deg2Rad;
        Vector3 angularVelocity = angularDisplacement / Time.deltaTime;

        return angularVelocity;
    }
    
    /// <summary>
    /// 脚本添加方法
    /// </summary>
    /// <param name="go"></param>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public static T GetOrAdd<T>(this GameObject go) where T : Component
    {
        if (go.TryGetComponent<T>(out var component))
        {
            return component;
        }
        else
        {
            return go.AddComponent<T>();
        }

    }
    
    public static T GetOrAdd<T>(this Transform go) where T : Component
    {
        if (go.TryGetComponent<T>(out var component))
        {
            return component;
        }
        else
        {
            return go.gameObject.AddComponent<T>();
        }

    }


    /// <summary>
    /// FNV-1a hash算法
    /// hash = offset_basis
    /// for each octet_of_data to be hashed
    /// hash = hash xor octet_of_data
    /// hash = hash * FNV_prime
    ///return hash
    /// </summary>
    /// <param name="str"></param>
    /// <returns></returns>
    public static int ComputeFNV1aHash(this string str)
    {
        uint hash = 2166136261;
        foreach (var c in str)
        {
            hash = (hash ^ c) * 16777619;
        }
        return unchecked((int)hash);
    }

}
